<!DOCTYPE html>
<html  lang="zh-CN" >
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, maximum-scale=5, viewport-fit=cover">
    <title>动态数据源使用@transaction注解后选库失效 | 学为我用</title>
    <meta name="description" content="背景项目使用了动态数据源，并且动态数据源的实现是自己实现的，支持了注解定义和包名配置定义。目前项目使用了4个数据源，以下为yml配置 12345678910111213141516171819202122232425262728293031323334353637383940414243spring:  datasource:    druid:      stat-view-servlet:">
<meta property="og:type" content="article">
<meta property="og:title" content="动态数据源使用@transaction注解后选库失效">
<meta property="og:url" content="https://123zhangzhenbin.gitee.io/zzbomb/2020/09/18/202009171800-dynamic-datasource-with-transaction/index.html">
<meta property="og:site_name" content="学为我用">
<meta property="og:description" content="背景项目使用了动态数据源，并且动态数据源的实现是自己实现的，支持了注解定义和包名配置定义。目前项目使用了4个数据源，以下为yml配置 12345678910111213141516171819202122232425262728293031323334353637383940414243spring:  datasource:    druid:      stat-view-servlet:">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2020-09-18T07:15:32.000Z">
<meta property="article:modified_time" content="2020-10-09T06:20:09.708Z">
<meta property="article:author" content="章瑱彬">
<meta property="article:tag" content="java">
<meta name="twitter:card" content="summary">

    
    <link rel="icon" href="/zzbomb/images/favicon_128.ico" type="image/x-icon">

    
<link rel="stylesheet" href="/zzbomb/css/common.min.css">



    
    
    
    
        <link href="//cdn.jsdelivr.net/npm/lightgallery.js@1.1.3/dist/css/lightgallery.min.css" rel="stylesheet">
    
    
    
<link rel="stylesheet" href="/zzbomb/css/iconfont.min.css">

    
<meta name="generator" content="Hexo 4.2.1"></head>

    <body>
        <header class="header header-fixture">
    <div class="profile-search-wrap flex sm:block">
        
        
        <div class="profile sm:text-center md:px-1 lg:px-3 sm:pb-4 sm:pt-6">
            <a id="avatar" role="link" href="https://gitee.com/123zhangzhenbin" class="inline-block lg:w-16 lg:h-16 w-8 h-8 m-2" target="_blank" rel="noopener" rel="noreferrer" >
                <img src="/zzbomb/images/g.jpg" class="rounded-full" alt="avatar">
            </a>
            <h2 id="name" class="hidden lg:block">ZZB</h2>
            <h3 id="title" class="hidden xl:block">Java，大数据，人工智能，区块链</h3>
            
            <small id="location" class="hidden lg:block">
                <i class="iconfont icon-map-icon"></i>
                DongGuan, China
            </small>
            
        </div>
        
        
<div class="search flex-1 flex lg:inline-block sm:hidden lg:px-4 lg:mt-2 lg:mb-4 lg:w-full">
    <form id="search-form" class="my-auto flex-1 lg:border lg:border-solid lg:border-gray-200">
        <div class="input-group table bg-gray-100 lg:bg-white w-full">
            <input id="search-input" type="text" placeholder="搜索" class="inline-block w-full bg-gray-100 lg:bg-white">
            <span class="table-cell">
                <button name="search tigger button" disabled>
                    <i class="iconfont icon-search m-2"></i>
                </button>
            </span>
        </div>
    </form>
        
<script id="search-teamplate" type="text/html" data-path="/zzbomb/content.json">
    <div>
        <div class="search-header bg-gray-400">
            <input id="actual-search-input" model="keyword" ref="input" class="inline-block w-full h-10 px-2 py-1" placeholder="搜索" type="text">
        </div>
        <div class="search-result bg-gray-200">
            {{#each searchPosts}}
            <a href="/{{ path }}" class="result-item block px-2 pb-3 mb-1 pt-1 hover:bg-indigo-100">
                <i class="iconfont icon-file"></i>
                <h1 class="result-title inline font-medium text-lg">{{ title }}</h1>
                <p class="result-content text-gray-600 text-sm">{{{ text }}}</p>
            </a>
            {{/each}}
        </div>
    </div>
</script>

</div>


        <button name="menu toogle button" id="menu-toggle-btn" class="block sm:hidden p-3" role="button" aria-expanded="false">
            <i class="iconfont icon-hamburger"></i>
        </button>
    </div>
    <nav id="menu-nav" class="hidden sm:flex flex-col">
        
        
            <div class="menu-item menu-home" role="menuitem">
                <a href="/zzbomb/.">
                    <i class="iconfont icon-home" aria-hidden="true"></i>
                    <span class="menu-title">首页</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-archives" role="menuitem">
                <a href="/zzbomb/archives">
                    <i class="iconfont icon-archive" aria-hidden="true"></i>
                    <span class="menu-title">归档</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-categories" role="menuitem">
                <a href="/zzbomb/categories">
                    <i class="iconfont icon-folder" aria-hidden="true"></i>
                    <span class="menu-title">分类</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-tags" role="menuitem">
                <a href="/zzbomb/tags">
                    <i class="iconfont icon-tag" aria-hidden="true"></i>
                    <span class="menu-title">标签</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-repository" role="menuitem">
                <a href="/zzbomb/repository">
                    <i class="iconfont icon-project" aria-hidden="true"></i>
                    <span class="menu-title">项目</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-links" role="menuitem">
                <a href="/zzbomb/links">
                    <i class="iconfont icon-friend" aria-hidden="true"></i>
                    <span class="menu-title">友链</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-about" role="menuitem">
                <a href="/zzbomb/about">
                    <i class="iconfont icon-cup" aria-hidden="true"></i>
                    <span class="menu-title">关于</span>
                </a>
            </div>
        
        
<div class="social-links flex sm:flex-col lg:hidden mt-5">
    
        <span class="social-item text-center">
            <a href="https://gitee.com/123zhangzhenbin" target="_blank" rel="noopener">
                <i class="iconfont social-icon icon-github"></i>
                <span class="menu-title hidden lg:inline">menu.github</span>
            </a>
        </span>
    
</div>


    </nav>
</header>

        <section class="main-section">
            
    <main class="flex-1 px-4 py-12 md:px-5 lg:px-8 lg:py-4 relative min-h-screen">
    

    <article class="content article article-archives article-type-list" itemscope="">
        <header class="article-header">
            
    
        <h1 class="article-title text-lg" itemprop="name">
            动态数据源使用@transaction注解后选库失效
        </h1>
    



            <p class="article-meta mb-3 text-xs">
                <span class="article-date">
    <i class="iconfont icon-calendar-check"></i>
	<a href="/zzbomb/2020/09/18/202009171800-dynamic-datasource-with-transaction/" class="article-date">
	  <time datetime="2020-09-18T07:15:32.000Z" itemprop="datePublished">9月 18</time>
	</a>
</span>

                

                
    <span class="article-tags">
    <i class="iconfont icon-tag"></i>
    <a class="article-tag-link" href="/zzbomb/tags/java/" rel="tag">java</a>
  </span>


                <span class="_partial/post-comment"><i class="icon icon-comment"></i>
                    <a href="/zzbomb/2020/09/18/202009171800-dynamic-datasource-with-transaction/#comments" class="article-comment-link">
                        评论
                    </a>
                </span>
                

            </p>
        </header>
        <div class="marked-body article-body">
            <h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>项目使用了动态数据源，并且动态数据源的实现是自己实现的，支持了注解定义和包名配置定义。<br>目前项目使用了4个数据源，以下为yml配置</p>
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><code class="hljs less"><span class="hljs-attribute">spring</span>:<br>  <span class="hljs-attribute">datasource</span>:<br>    <span class="hljs-attribute">druid</span>:<br>      <span class="hljs-attribute">stat-view-servlet</span>:<br>        <span class="hljs-attribute">loginUsername</span>: admin<br>        <span class="hljs-attribute">loginPassword</span>: <span class="hljs-number">123456</span><br>    <span class="hljs-attribute">dynamic</span>:<br>      <span class="hljs-attribute">druid</span>: #以下是全局默认值，可以全局更改<br>        <span class="hljs-attribute">initial-size</span>: <span class="hljs-number">1</span><br>        <span class="hljs-attribute">max-active</span>: <span class="hljs-number">30</span><br>        <span class="hljs-attribute">min-idle</span>: <span class="hljs-number">1</span><br>        <span class="hljs-attribute">max-wait</span>: <span class="hljs-number">30000</span><br>        <span class="hljs-attribute">time-between-eviction-runs-millis</span>: <span class="hljs-number">100</span><br>        <span class="hljs-attribute">test-while-idle</span>: true<br>        <span class="hljs-attribute">validation-query</span>: SELECT <span class="hljs-string">'X'</span><br>        <span class="hljs-attribute">validation-query-timeout</span>: <span class="hljs-number">10000</span><br>        <span class="hljs-attribute">max-wait-thread-count</span>: <span class="hljs-number">10</span><br>        <span class="hljs-attribute">keep-alive</span>: true<br>        <span class="hljs-attribute">phy-timeout-millis</span>: <span class="hljs-number">300000</span><br>        <span class="hljs-attribute">pool-prepared-statements</span>: false<br>        <span class="hljs-attribute">filters</span>: stat<br>      <span class="hljs-attribute">primary</span>: pdservermanager # 默认主库<br>      <span class="hljs-attribute">datasource</span>:<br>        <span class="hljs-attribute">pdservermanager</span>: # web通用框架库<br>          <span class="hljs-attribute">driver-class-name</span>: com.mysql.jdbc.Driver<br>          <span class="hljs-attribute">password</span>: yi2345liu<br>          <span class="hljs-attribute">url</span>: <span class="hljs-attribute">jdbc</span>:<span class="hljs-attribute">mysql</span>:<span class="hljs-comment">//127.0.0.1:3306/db_pdserver_manager?zeroDateTimeBehavior=convertToNull&amp;useUnicode=true&amp;characterEncoding=utf-8</span><br>          <span class="hljs-attribute">username</span>: root<br>        <span class="hljs-attribute">pdserver</span>: # 业务库<br>          <span class="hljs-attribute">driver-class-name</span>: com.mysql.jdbc.Driver<br>          <span class="hljs-attribute">password</span>: yi2345liu<br>          <span class="hljs-attribute">url</span>: <span class="hljs-attribute">jdbc</span>:<span class="hljs-attribute">mysql</span>:<span class="hljs-comment">//127.0.0.1:3306/pdserver_authority_control_x?zeroDateTimeBehavior=convertToNull&amp;useUnicode=true&amp;characterEncoding=utf-8</span><br>          <span class="hljs-attribute">username</span>: root<br>        <span class="hljs-attribute">oldpdserver</span>: # 业务库<span class="hljs-number">2</span><br>          <span class="hljs-attribute">driver-class-name</span>: com.mysql.jdbc.Driver<br>          <span class="hljs-attribute">password</span>: Myjadmin<span class="hljs-variable">@25588</span>!@#<br>          <span class="hljs-attribute">url</span>: <span class="hljs-attribute">jdbc</span>:<span class="hljs-attribute">mysql</span>:<span class="hljs-comment">//127.0.0.1:13306/pdserver_authority_control?zeroDateTimeBehavior=convertToNull&amp;useUnicode=true&amp;characterEncoding=utf-8</span><br>          <span class="hljs-attribute">username</span>: root<br>        <span class="hljs-attribute">xxljob</span>: # xxljob 定时作业库<br>          <span class="hljs-attribute">driver-class-name</span>: com.mysql.jdbc.Driver<br>          <span class="hljs-attribute">password</span>: yi2345liu<br>          <span class="hljs-attribute">url</span>: <span class="hljs-attribute">jdbc</span>:<span class="hljs-attribute">mysql</span>:<span class="hljs-comment">//127.0.0.1:3306/xxl-job_x?zeroDateTimeBehavior=convertToNull&amp;useUnicode=true&amp;characterEncoding=utf-8</span><br>          <span class="hljs-attribute">username</span>: root<br></code></pre></td></tr></table></figure>

<p>在业务相关的myBatis的Mapper接口上使用了@DS注解来指定数据源</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/*</span><br><span class="hljs-comment"> * API配置 Mapper接口</span><br><span class="hljs-comment"> * @author : ZZB</span><br><span class="hljs-comment"> * @since : 2020-03-09 09:59:34</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Mapper</span><br><span class="hljs-meta">@DS</span>(<span class="hljs-string">"pdserver"</span>)<br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">ApiConfigMapper</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BaseMapper</span>&lt;<span class="hljs-title">ApiConfig</span>&gt; </span>&#123;...&#125;<br><br><span class="hljs-comment">/*</span><br><span class="hljs-comment"> * 元数据服务器 Mapper接口</span><br><span class="hljs-comment"> * @author : ZZB</span><br><span class="hljs-comment"> * @since : 2019-09-17 09:24:29</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Mapper</span><br><span class="hljs-meta">@DS</span>(<span class="hljs-string">"oldpdserver"</span>)<br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">DataCollectionDbMapper</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BaseMapper</span>&lt;<span class="hljs-title">DataCollectionDb</span>&gt; </span>&#123;...&#125;<br></code></pre></td></tr></table></figure>
<p>其他通用依赖使用配置的方式指定数据源，通过 DynamicConfiguration 实现</p>
<p>DynamicConfiguration.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Configuration</span><br><span class="hljs-meta">@AutoConfigureBefore</span>(XxlJobAdminConfig<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span><br><span class="hljs-class">@<span class="hljs-title">Import</span>(<span class="hljs-title">DruidDynamicDataSourceConfiguration</span>.<span class="hljs-title">class</span>)</span><br><span class="hljs-class"><span class="hljs-title">public</span> <span class="hljs-title">class</span> <span class="hljs-title">DynamicConfiguration</span> </span>&#123;<br><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> DynamicDataSourceConfigure <span class="hljs-title">dynamicDataSourceConfigure</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> DynamicDataSourceConfigure.config()<br>                .regexMatchers(<span class="hljs-string">"com.zzb.framework.modules.*"</span>,<span class="hljs-string">"pdservermanager"</span>)<br>                .regexMatchers(<span class="hljs-string">"com.xxl.job.*"</span>, <span class="hljs-string">"xxljob"</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>DynamicDataSourceAutoConfiguration.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 动态数据源核心自动配置类</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Slf</span>4j<br><span class="hljs-meta">@Configuration</span><br><span class="hljs-meta">@EnableConfigurationProperties</span>(DynamicDataSourceProperties<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span><br><span class="hljs-class"><span class="hljs-title">public</span> <span class="hljs-title">class</span> <span class="hljs-title">DynamicDataSourceAutoConfiguration</span> </span>&#123;<br><br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> DynamicDataSourceProperties properties;<br><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-meta">@ConditionalOnMissingBean</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> DynamicDataSourceProvider <span class="hljs-title">dynamicDataSourceProvider</span><span class="hljs-params">(DynamicDataSourceCreator dynamicDataSourceCreator)</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> YmlDynamicDataSourceProvider(properties, dynamicDataSourceCreator);<br>    &#125;<br><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-meta">@ConditionalOnMissingBean</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> DynamicDataSourceCreator <span class="hljs-title">dynamicDataSourceCreator</span><span class="hljs-params">(@Autowired WebApplicationContext webApplicationContext)</span> </span>&#123;<br>        DynamicDataSourceCreator dynamicDataSourceCreator = <span class="hljs-keyword">new</span> DynamicDataSourceCreator();<br>        dynamicDataSourceCreator.setApplicationContext(webApplicationContext);<br>        dynamicDataSourceCreator.setDruidGlobalConfig(properties.getDruid());<br>        dynamicDataSourceCreator.setHikariGlobalConfig(properties.getHikari());<br>        <span class="hljs-keyword">return</span> dynamicDataSourceCreator;<br>    &#125;<br><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-meta">@ConditionalOnMissingBean</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> DataSource <span class="hljs-title">dataSource</span><span class="hljs-params">(DynamicDataSourceProvider dynamicDataSourceProvider)</span> </span>&#123;<br>        DynamicRoutingDataSource dataSource = <span class="hljs-keyword">new</span> DynamicRoutingDataSource();<br>        dataSource.setPrimary(properties.getPrimary());<br>        dataSource.setStrategy(properties.getStrategy());<br>        dataSource.setProvider(dynamicDataSourceProvider);<br>        dataSource.setP6spy(properties.getP6spy());<br>        dataSource.setStrict(properties.getStrict());<br>        <span class="hljs-keyword">return</span> dataSource;<br>    &#125;<br><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-meta">@ConditionalOnMissingBean</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> DynamicDataSourceAnnotationAdvisor <span class="hljs-title">dynamicDatasourceAnnotationAdvisor</span><span class="hljs-params">(DsProcessor dsProcessor)</span> </span>&#123;<br>        DynamicDataSourceAnnotationInterceptor interceptor = <span class="hljs-keyword">new</span> DynamicDataSourceAnnotationInterceptor();<br>        interceptor.setDsProcessor(dsProcessor);<br>        DynamicDataSourceAnnotationAdvisor advisor = <span class="hljs-keyword">new</span> DynamicDataSourceAnnotationAdvisor(interceptor);<br>        advisor.setOrder(properties.getOrder());<br>        <span class="hljs-keyword">return</span> advisor;<br>    &#125;<br><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-meta">@ConditionalOnMissingBean</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> DsProcessor <span class="hljs-title">dsProcessor</span><span class="hljs-params">()</span> </span>&#123;<br>        DsHeaderProcessor headerProcessor = <span class="hljs-keyword">new</span> DsHeaderProcessor();<br>        DsSessionProcessor sessionProcessor = <span class="hljs-keyword">new</span> DsSessionProcessor();<br>        DsSpelExpressionProcessor spelExpressionProcessor = <span class="hljs-keyword">new</span> DsSpelExpressionProcessor();<br>        headerProcessor.setNextProcessor(sessionProcessor);<br>        sessionProcessor.setNextProcessor(spelExpressionProcessor);<br>        <span class="hljs-keyword">return</span> headerProcessor;<br>    &#125;<br><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> PdDynamicDataSourceAdvisor <span class="hljs-title">dynamicAdvisor</span><span class="hljs-params">(DynamicDataSourceConfigure dynamicDataSourceConfigure, DsProcessor dsProcessor)</span> </span>&#123;<br>        PdDynamicDataSourceAdvisor advisor = <span class="hljs-keyword">new</span> PdDynamicDataSourceAdvisor(dynamicDataSourceConfigure.getMatchers());<br>        advisor.setDsProcessor(dsProcessor);<br>        <span class="hljs-keyword">return</span> advisor;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>PdDynamicDataSourceAdvisor.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 动态数据源切面</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Slf</span>4j<br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PdDynamicDataSourceAdvisor</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AbstractPointcutAdvisor</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BeanFactoryAware</span>  </span>&#123;<br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * SPEL参数标识</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String DYNAMIC_PREFIX = <span class="hljs-string">"#"</span>;<br><br>    <span class="hljs-meta">@Setter</span><br>    <span class="hljs-keyword">private</span> DsProcessor dsProcessor;<br><br>    <span class="hljs-keyword">private</span> Advice advice;<br><br>    <span class="hljs-keyword">private</span> Pointcut pointcut;<br><br>    <span class="hljs-keyword">private</span> Map&lt;String, String&gt; matchesCache = <span class="hljs-keyword">new</span> HashMap&lt;String, String&gt;();<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">PdDynamicDataSourceAdvisor</span><span class="hljs-params">(List&lt;Matcher&gt; matchers)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.pointcut = buildPointcut(matchers);<br>        <span class="hljs-keyword">this</span>.advice = buildAdvice();<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">private</span> Advice <span class="hljs-title">buildAdvice</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> (MethodInterceptor) invocation -&gt; &#123;<br>            String key = <span class="hljs-keyword">null</span>;<br>            <span class="hljs-keyword">try</span> &#123;<br>                Method method = invocation.getMethod();<br>                String clazzName = invocation.getThis().getClass().getName();<br>                <span class="hljs-keyword">if</span>(clazzName.startsWith(<span class="hljs-string">"com.sun.proxy."</span>))&#123;<br>                    clazzName = method.getDeclaringClass().getName();<br>                &#125;<br>                String methodPath = clazzName + <span class="hljs-string">"."</span> + method.getName();<br>                log.debug(<span class="hljs-string">"PdDynamicDataSourceAdvisor methodPath : &#123;&#125;"</span> ,methodPath );<br>                key = matchesCache.get(methodPath);<br>                <span class="hljs-keyword">if</span>(key == <span class="hljs-keyword">null</span>) &#123;<br>                    <span class="hljs-keyword">if</span> (invocation <span class="hljs-keyword">instanceof</span> ReflectiveMethodInvocation) &#123;<br>                        methodPath =method.getDeclaringClass().getName().replace(<span class="hljs-string">"."</span>,<span class="hljs-string">"\\."</span>) + <span class="hljs-string">"\\$\\$EnhancerBySpringCGLIB\\$\\$(.*)\\."</span> + method.getName();<br>                        Pattern pattern = Pattern.compile(methodPath);<br>                        String matchesCacheKey = matchesCache.keySet().stream().filter(s -&gt; &#123;<br>                            java.util.regex.Matcher matcher = pattern.matcher(s);<br>                            <span class="hljs-keyword">return</span> matcher.find();<br>                        &#125;).findFirst().orElse(<span class="hljs-keyword">null</span>);<br>                        <span class="hljs-keyword">if</span>(matchesCacheKey != <span class="hljs-keyword">null</span>)&#123;<br>                            key = matchesCache.get(matchesCacheKey);<br>                        &#125; <span class="hljs-keyword">else</span> &#123;<br>                            ReflectiveMethodInvocation reflectiveMethodInvocation = (ReflectiveMethodInvocation) invocation;<br>                            log.debug(<span class="hljs-string">"datasource inject error : methodPath is &#123;&#125; ,  method.class is &#123;&#125;, method.name is &#123;&#125; , proxy class is &#123;&#125; "</span><br>                                    ,methodPath,method.getDeclaringClass().getName(), method.getName(),reflectiveMethodInvocation.getProxy().getClass());<br>                        &#125;<br>                    &#125; <span class="hljs-keyword">else</span> &#123;<br>                        log.debug(<span class="hljs-string">"datasource inject error : invocation is not a instance of ReflectiveMethodInvocation, and methodPath is &#123;&#125;"</span>,methodPath);<br>                    &#125;<br>                &#125;<br>                <span class="hljs-keyword">if</span> (key != <span class="hljs-keyword">null</span> &amp;&amp; !key.isEmpty() &amp;&amp; key.startsWith(DYNAMIC_PREFIX)) &#123;<br>                    key = dsProcessor.determineDatasource(invocation, key);<br>                &#125;<br>                <span class="hljs-keyword">if</span>(key != <span class="hljs-keyword">null</span>) &#123;<br>                    DynamicDataSourceContextHolder.push(key);<br>                &#125;<br>                <span class="hljs-keyword">return</span> invocation.proceed();<br>            &#125; <span class="hljs-keyword">finally</span> &#123;<br>                <span class="hljs-keyword">if</span>(key != <span class="hljs-keyword">null</span>) &#123;<br>                    DynamicDataSourceContextHolder.poll();<br>                &#125;<br>            &#125;<br>        &#125;;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> Pointcut <span class="hljs-title">getPointcut</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.pointcut;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> Advice <span class="hljs-title">getAdvice</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.advice;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setBeanFactory</span><span class="hljs-params">(BeanFactory beanFactory)</span> <span class="hljs-keyword">throws</span> BeansException </span>&#123;<br>        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.advice <span class="hljs-keyword">instanceof</span> BeanFactoryAware) &#123;<br>            ((BeanFactoryAware) <span class="hljs-keyword">this</span>.advice).setBeanFactory(beanFactory);<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">private</span> Pointcut <span class="hljs-title">buildPointcut</span><span class="hljs-params">(List&lt;Matcher&gt; matchers)</span> </span>&#123;<br>        ComposablePointcut composablePointcut = <span class="hljs-keyword">null</span>;<br>        <span class="hljs-keyword">for</span> (Matcher matcher : matchers) &#123;<br>            <span class="hljs-keyword">if</span> (matcher <span class="hljs-keyword">instanceof</span> RegexMatcher) &#123;<br>                RegexMatcher regexMatcher = (RegexMatcher) matcher;<br>                Pointcut pointcut = <span class="hljs-keyword">new</span> DynamicJdkRegexpMethodPointcut(regexMatcher.getPattern(), regexMatcher.getDs(), matchesCache);<br>                <span class="hljs-keyword">if</span> (composablePointcut == <span class="hljs-keyword">null</span>) &#123;<br>                    composablePointcut = <span class="hljs-keyword">new</span> ComposablePointcut(pointcut);<br>                &#125; <span class="hljs-keyword">else</span> &#123;<br>                    composablePointcut.union(pointcut);<br>                &#125;<br>            &#125; <span class="hljs-keyword">else</span> &#123;<br>                ExpressionMatcher expressionMatcher = (ExpressionMatcher) matcher;<br>                Pointcut pointcut = <span class="hljs-keyword">new</span> DynamicAspectJExpressionPointcut(expressionMatcher.getExpression(), expressionMatcher.getDs(), matchesCache);<br>                <span class="hljs-keyword">if</span> (composablePointcut == <span class="hljs-keyword">null</span>) &#123;<br>                    composablePointcut = <span class="hljs-keyword">new</span> ComposablePointcut(pointcut);<br>                &#125; <span class="hljs-keyword">else</span> &#123;<br>                    composablePointcut.union(pointcut);<br>                &#125;<br>            &#125;<br>        &#125;<br>        <span class="hljs-keyword">return</span> composablePointcut;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setOrder</span><span class="hljs-params">(<span class="hljs-keyword">int</span> order)</span> </span>&#123;<br>        <span class="hljs-keyword">super</span>.setOrder(Ordered.HIGHEST_PRECEDENCE);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>


<p>由于spring中，mybatis中，druid中，mybatisplus中，均有数据源的实现，所以需要在配置中特别排除掉</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs yml"><span class="hljs-attr">spring:</span><br>  <span class="hljs-attr">autoconfigure:</span><br>    <span class="hljs-attr">exclude:</span> <span class="hljs-string">com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration,com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure,org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration</span><br></code></pre></td></tr></table></figure>
<p>这样一来，默认的就只剩下我们自定义的动态数据源策略了，通过<br>DynamicDataSourceAnnotationAdvisor和PdDynamicDataSourceAdvisor同时支持了注解和指定数据源的方式。</p>
<p>这时在没使用@Transaction的情况下可以任意切换数据源，但是如果使用了@Transaction，在事务体中会失效，而使用第一个数据源。</p>
<h2 id="重现"><a href="#重现" class="headerlink" title="重现"></a>重现</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br></pre></td><td class="code"><pre><code class="hljs log">2020-09-18 15:54:55.884 ERROR &#123;&quot;thread&quot;:&quot;http-nio-9090-exec-11&quot;,&quot;className&quot;:&quot;com.meiyijia.pd.admin.controller.FastDataTunnelJobConfigController&quot;,&quot;methodName&quot;:&quot;add&quot;,&quot;codeLine&quot;:&quot;79&quot;&#125;|-&gt; <br>### Error querying database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table &#39;pdserver_authority_control_x.t_sys_param&#39; doesn&#39;t exist<br>### The error may exist in com&#x2F;zzb&#x2F;framework&#x2F;modules&#x2F;param&#x2F;dao&#x2F;mapper&#x2F;SysParamMapper.java (best guess)<br>### The error may involve defaultParameterMap<br>### The error occurred while setting parameters<br>### SQL: SELECT  id,param_key,param_value,remark,overt,creator,updater,create_time,update_time,activate,operation_version  FROM t_sys_param   WHERE  activate&#x3D;1  AND param_key &#x3D; ? ORDER BY create_time DESC limit 1<br>### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table &#39;pdserver_authority_control_x.t_sys_param&#39; doesn&#39;t exist<br>; bad SQL grammar []; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table &#39;pdserver_authority_control_x.t_sys_param&#39; doesn&#39;t exist<br>org.springframework.jdbc.BadSqlGrammarException: <br>### Error querying database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table &#39;pdserver_authority_control_x.t_sys_param&#39; doesn&#39;t exist<br>### The error may exist in com&#x2F;zzb&#x2F;framework&#x2F;modules&#x2F;param&#x2F;dao&#x2F;mapper&#x2F;SysParamMapper.java (best guess)<br>### The error may involve defaultParameterMap<br>### The error occurred while setting parameters<br>### SQL: SELECT  id,param_key,param_value,remark,overt,creator,updater,create_time,update_time,activate,operation_version  FROM t_sys_param   WHERE  activate&#x3D;1  AND param_key &#x3D; ? ORDER BY create_time DESC limit 1<br>### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table &#39;pdserver_authority_control_x.t_sys_param&#39; doesn&#39;t exist<br>; bad SQL grammar []; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table &#39;pdserver_authority_control_x.t_sys_param&#39; doesn&#39;t exist<br>	at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:234)<br>	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)<br>	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)<br>	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)<br>	at com.sun.proxy.$Proxy72.selectList(Unknown Source)<br>	at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:230)<br>	at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:158)<br>	at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:76)<br>	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:62)<br>	at com.sun.proxy.$Proxy137.selectList(Unknown Source)<br>	at com.zzb.framework.modules.param.dao.SysParamDAO.findTopByParamKey(SysParamDAO.java:23)<br>	at com.zzb.framework.modules.param.dao.SysParamDAO$$FastClassBySpringCGLIB$$ad0c2505.invoke(&lt;generated&gt;)<br>	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)<br>	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)<br>	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)<br>	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)<br>	at com.zzb.framework.starter.xxljob.conf.datasource.PdDynamicDataSourceAdvisor.lambda$buildAdvice$1(PdDynamicDataSourceAdvisor.java:90)<br>	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)<br>	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)<br>	at com.zzb.framework.modules.param.dao.SysParamDAO$$EnhancerBySpringCGLIB$$b2550370.findTopByParamKey(&lt;generated&gt;)<br>	at com.zzb.framework.modules.param.service.SysParamService.get(SysParamService.java:77)<br>	at com.zzb.framework.modules.param.service.SysParamService$$FastClassBySpringCGLIB$$1c77584b.invoke(&lt;generated&gt;)<br>	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)<br>	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)<br>	at com.zzb.framework.starter.xxljob.conf.datasource.PdDynamicDataSourceAdvisor.lambda$buildAdvice$1(PdDynamicDataSourceAdvisor.java:90)<br>	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)<br>	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)<br>	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)<br>	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)<br>	at com.zzb.framework.modules.param.service.SysParamService$$EnhancerBySpringCGLIB$$9c4e1041.get(&lt;generated&gt;)<br>	at com.meiyijia.pd.admin.service.FastDataTunnelJobConfigService.saveXxlJobInfo(FastDataTunnelJobConfigService.java:289)<br>	at com.meiyijia.pd.admin.service.FastDataTunnelJobConfigService.saveAndCreateJob(FastDataTunnelJobConfigService.java:189)<br>	at com.meiyijia.pd.admin.service.FastDataTunnelJobConfigService$$FastClassBySpringCGLIB$$682460f6.invoke(&lt;generated&gt;)<br>	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)<br>	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)<br>	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295)<br>	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)<br>	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)<br>	at com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationInterceptor.invoke(DynamicDataSourceAnnotationInterceptor.java:52)<br>	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)<br>	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)<br>	at com.meiyijia.pd.admin.service.FastDataTunnelJobConfigService$$EnhancerBySpringCGLIB$$2701c93a.saveAndCreateJob(&lt;generated&gt;)<br>	at com.meiyijia.pd.admin.controller.FastDataTunnelJobConfigController.add(FastDataTunnelJobConfigController.java:77)<br>	at com.meiyijia.pd.admin.controller.FastDataTunnelJobConfigController$$FastClassBySpringCGLIB$$90a96474.invoke(&lt;generated&gt;)<br>	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)<br>	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)<br>	at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)<br>	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)<br>	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)<br>	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)<br>	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)<br>	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)<br>	at com.meiyijia.pd.admin.controller.FastDataTunnelJobConfigController$$EnhancerBySpringCGLIB$$fb330760.add(&lt;generated&gt;)<br>	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)<br>	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)<br>	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)<br>	at java.lang.reflect.Method.invoke(Method.java:498)<br>	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)<br>	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)<br>	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)<br>	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)<br>	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)<br>	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)<br>	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)<br>	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)<br>	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)<br>	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)<br>	at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)<br>	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)<br>	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)<br>	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)<br>	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)<br>	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)<br>	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)<br>	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)<br>	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:112)<br>	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)<br>	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)<br>	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)<br>	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)<br>	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)<br>	at com.zzb.framework.xss.XssFilter.doFilter(XssFilter.java:30)<br>	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)<br>	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)<br>	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)<br>	at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)<br>	at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)<br>	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)<br>	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)<br>	at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)<br>	at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)<br>	at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)<br>	at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)<br>	at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:387)<br>	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)<br>	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)<br>	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)<br>	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)<br>	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)<br>	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)<br>	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)<br>	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)<br>	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)<br>	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)<br>	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)<br>	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)<br>	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)<br>	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)<br>	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)<br>	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)<br>	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)<br>	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)<br>	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)<br>	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)<br>	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)<br>	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)<br>	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)<br>	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)<br>	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)<br>	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)<br>	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)<br>	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)<br>	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)<br>	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)<br>	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)<br>	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)<br>	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)<br>	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)<br>	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)<br>	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)<br>	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)<br>	at java.lang.Thread.run(Thread.java:748)<br>Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table &#39;pdserver_authority_control_x.t_sys_param&#39; doesn&#39;t exist<br>	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)<br>	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)<br>	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)<br>	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)<br>	at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)<br>	at com.mysql.jdbc.Util.getInstance(Util.java:408)<br>	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:943)<br>	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3973)<br>	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3909)<br>	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2527)<br>	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2680)<br>	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2487)<br>	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1858)<br>	at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1197)<br>	at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3409)<br>	at com.alibaba.druid.filter.FilterEventAdapter.preparedStatement_execute(FilterEventAdapter.java:440)<br>	at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3407)<br>	at com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl.execute(PreparedStatementProxyImpl.java:167)<br>	at com.alibaba.druid.pool.DruidPooledPreparedStatement.execute(DruidPooledPreparedStatement.java:498)<br>	at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:64)<br>	at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79)<br>	at sun.reflect.GeneratedMethodAccessor121.invoke(Unknown Source)<br>	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)<br>	at java.lang.reflect.Method.invoke(Method.java:498)<br>	at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63)<br>	at com.sun.proxy.$Proxy195.query(Unknown Source)<br>	at com.baomidou.mybatisplus.core.executor.MybatisSimpleExecutor.doQuery(MybatisSimpleExecutor.java:67)<br>	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:324)<br>	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)<br>	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:136)<br>	at sun.reflect.GeneratedMethodAccessor119.invoke(Unknown Source)<br>	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)<br>	at java.lang.reflect.Method.invoke(Method.java:498)<br>	at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63)<br>	at com.sun.proxy.$Proxy194.query(Unknown Source)<br>	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)<br>	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)<br>	at sun.reflect.GeneratedMethodAccessor124.invoke(Unknown Source)<br>	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)<br>	at java.lang.reflect.Method.invoke(Method.java:498)<br>	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433)<br>	... 143 common frames omitted<br></code></pre></td></tr></table></figure>

<h2 id="DEBUG定位"><a href="#DEBUG定位" class="headerlink" title="DEBUG定位"></a>DEBUG定位</h2><p>通过日志分析，我们知道，Mysql真实statement是在com.baomidou.mybatisplus.core.executor.MybatisSimpleExecutor.java:67行附近实现的，于是定位到对应代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">public</span> &lt;E&gt; <span class="hljs-function">List&lt;E&gt; <span class="hljs-title">doQuery</span><span class="hljs-params">(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)</span> <span class="hljs-keyword">throws</span> SQLException </span>&#123;<br>    Statement stmt = <span class="hljs-keyword">null</span>;<br>    <span class="hljs-keyword">try</span> &#123;<br>        Configuration configuration = ms.getConfiguration();<br>        StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);<br>        stmt = prepareStatement(handler, ms.getStatementLog(), <span class="hljs-keyword">false</span>); <span class="hljs-comment">// 这里获取stmt</span><br>        <span class="hljs-keyword">return</span> stmt == <span class="hljs-keyword">null</span> ? Collections.emptyList() : handler.query(stmt, resultHandler);<br>    &#125; <span class="hljs-keyword">finally</span> &#123;<br>        closeStatement(stmt);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>通过prepareStatement获取stmt</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs java"> <span class="hljs-function"><span class="hljs-keyword">private</span> Statement <span class="hljs-title">prepareStatement</span><span class="hljs-params">(StatementHandler handler, Log statementLog, <span class="hljs-keyword">boolean</span> isCursor)</span> <span class="hljs-keyword">throws</span> SQLException </span>&#123;<br>    Statement stmt;<br>    Connection connection = getConnection(statementLog); <span class="hljs-comment">// 获取连接</span><br>    stmt = handler.prepare(connection, transaction.getTimeout());<br>    <span class="hljs-comment">//游标不支持返回null.</span><br>    <span class="hljs-keyword">if</span> (stmt == <span class="hljs-keyword">null</span> &amp;&amp; !isCursor) &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;<br>    &#125; <span class="hljs-keyword">else</span> &#123;<br>        handler.parameterize(stmt);<br>        <span class="hljs-keyword">return</span> stmt;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>再通过getConnection获取连接，代码在org.apache.ibatis.executor.BaseExecutor.java中<br>是个抽象类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">protected</span> Connection <span class="hljs-title">getConnection</span><span class="hljs-params">(Log statementLog)</span> <span class="hljs-keyword">throws</span> SQLException </span>&#123;<br>    Connection connection = transaction.getConnection(); <span class="hljs-comment">// 通过事务获取连接</span><br>    <span class="hljs-keyword">if</span> (statementLog.isDebugEnabled()) &#123;<br>    <span class="hljs-keyword">return</span> ConnectionLogger.newInstance(connection, statementLog, queryStack);<br>    &#125; <span class="hljs-keyword">else</span> &#123;<br>    <span class="hljs-keyword">return</span> connection;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>得知是通过transaction获取连接的，这里的Transaction是个接口，通过debug，找到是SpringManagedTransaction实现类。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> Connection <span class="hljs-title">getConnection</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> SQLException </span>&#123;<br>    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.connection == <span class="hljs-keyword">null</span>) &#123;<br>        <span class="hljs-keyword">this</span>.openConnection();<br>    &#125;<br><br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.connection;<br>&#125;<br><br><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">openConnection</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> SQLException </span>&#123;<br>    <span class="hljs-keyword">this</span>.connection = DataSourceUtils.getConnection(<span class="hljs-keyword">this</span>.dataSource);<br>    <span class="hljs-keyword">this</span>.autoCommit = <span class="hljs-keyword">this</span>.connection.getAutoCommit();<br>    <span class="hljs-keyword">this</span>.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(<span class="hljs-keyword">this</span>.connection, <span class="hljs-keyword">this</span>.dataSource);<br>    <span class="hljs-keyword">if</span> (LOGGER.isDebugEnabled()) &#123;<br>        LOGGER.debug(<span class="hljs-string">"JDBC Connection ["</span> + <span class="hljs-keyword">this</span>.connection + <span class="hljs-string">"] will"</span> + (<span class="hljs-keyword">this</span>.isConnectionTransactional ? <span class="hljs-string">" "</span> : <span class="hljs-string">" not "</span>) + <span class="hljs-string">"be managed by Spring"</span>);<br>    &#125;<br><br>&#125;<br></code></pre></td></tr></table></figure>
<p>走到这里，我们已经知道是通过DataSourceUtils来获取连接的了，找到DataSourceUtils中的核心代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment">	 * Actually obtain a JDBC Connection from the given DataSource.</span><br><span class="hljs-comment">     通过数据源获取JDBC的真实连接</span><br><span class="hljs-comment">	 * Same as &#123;<span class="hljs-doctag">@link</span> #getConnection&#125;, but throwing the original SQLException.</span><br><span class="hljs-comment">     和getConnection方法一样，只不过本方法会抛出一个原始的SQLException</span><br><span class="hljs-comment">	 * &lt;p&gt;Is aware of a corresponding Connection bound to the current thread, for example</span><br><span class="hljs-comment">     获取绑定到当前线程的相应连接</span><br><span class="hljs-comment">	 * when using &#123;<span class="hljs-doctag">@link</span> DataSourceTransactionManager&#125;. Will bind a Connection to the thread</span><br><span class="hljs-comment">	 * if transaction synchronization is active (e.g. if in a JTA transaction).</span><br><span class="hljs-comment">     如果使用了事务，则把当前获取的链接 bind 到当前线程</span><br><span class="hljs-comment">	 * &lt;p&gt;Directly accessed by &#123;<span class="hljs-doctag">@link</span> TransactionAwareDataSourceProxy&#125;.</span><br><span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> dataSource the DataSource to obtain Connections from</span><br><span class="hljs-comment">	 * <span class="hljs-doctag">@return</span> a JDBC Connection from the given DataSource</span><br><span class="hljs-comment">	 * <span class="hljs-doctag">@throws</span> SQLException if thrown by JDBC methods</span><br><span class="hljs-comment">	 * <span class="hljs-doctag">@see</span> #doReleaseConnection</span><br><span class="hljs-comment">	 */</span><br>	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Connection <span class="hljs-title">doGetConnection</span><span class="hljs-params">(DataSource dataSource)</span> <span class="hljs-keyword">throws</span> SQLException </span>&#123;<br>		Assert.notNull(dataSource, <span class="hljs-string">"No DataSource specified"</span>);<br><br>		ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);<br>        <span class="hljs-comment">// 这一段代码就是检查是不是用了事务，如果是，就直接从conHolder中拿连接</span><br>		<span class="hljs-keyword">if</span> (conHolder != <span class="hljs-keyword">null</span> &amp;&amp; (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) &#123;<br>			conHolder.requested();<br>			<span class="hljs-keyword">if</span> (!conHolder.hasConnection()) &#123;<br>				logger.debug(<span class="hljs-string">"Fetching resumed JDBC Connection from DataSource"</span>);<br>				conHolder.setConnection(fetchConnection(dataSource));<br>			&#125;<br>			<span class="hljs-keyword">return</span> conHolder.getConnection();<br>		&#125;<br>		<span class="hljs-comment">// Else we either got no holder or an empty thread-bound holder here.</span><br><br>		logger.debug(<span class="hljs-string">"Fetching JDBC Connection from DataSource"</span>);<br>		Connection con = fetchConnection(dataSource);<br><br>		<span class="hljs-keyword">if</span> (TransactionSynchronizationManager.isSynchronizationActive()) &#123;<br>			<span class="hljs-keyword">try</span> &#123;<br>				<span class="hljs-comment">// Use same Connection for further JDBC actions within the transaction.</span><br>				<span class="hljs-comment">// Thread-bound object will get removed by synchronization at transaction completion.</span><br>				ConnectionHolder holderToUse = conHolder;<br>				<span class="hljs-keyword">if</span> (holderToUse == <span class="hljs-keyword">null</span>) &#123;<br>					holderToUse = <span class="hljs-keyword">new</span> ConnectionHolder(con);<br>				&#125;<br>				<span class="hljs-keyword">else</span> &#123;<br>					holderToUse.setConnection(con);<br>				&#125;<br>				holderToUse.requested();<br>				TransactionSynchronizationManager.registerSynchronization(<br>						<span class="hljs-keyword">new</span> ConnectionSynchronization(holderToUse, dataSource));<br>				holderToUse.setSynchronizedWithTransaction(<span class="hljs-keyword">true</span>);<br>				<span class="hljs-keyword">if</span> (holderToUse != conHolder) &#123;<br>					TransactionSynchronizationManager.bindResource(dataSource, holderToUse);<br>				&#125;<br>			&#125;<br>			<span class="hljs-keyword">catch</span> (RuntimeException ex) &#123;<br>				<span class="hljs-comment">// Unexpected exception from external delegation call -&gt; close Connection and rethrow.</span><br>				releaseConnection(con, dataSource);<br>				<span class="hljs-keyword">throw</span> ex;<br>			&#125;<br>		&#125;<br><br>		<span class="hljs-keyword">return</span> con;<br>	&#125;<br></code></pre></td></tr></table></figure>
<p>因此，会导致多数据源配置失效。</p>
<h2 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h2><p>典型的分布式事务，一般来说分布式事务有4种常用的解决方案</p>
<h3 id="两段事务提交"><a href="#两段事务提交" class="headerlink" title="两段事务提交"></a>两段事务提交</h3><p>两端事务中有一个事务管理器（TransactionManager）多个资源管理器（Resource Manager），二阶段提交是XA的标准实现。它将分布式事务的提交拆分为2个阶段：prepare和commit/rollback。两段事务比较慢，不适合并发高的场景。两阶段提交这种解决方案属于牺牲了一部分可用性来换取的一致性。三段提交是在两端提交的基础上，在开始的时候增加了一个询问操作，用来确保数据库的可用性，防止因参与集群异常导致的事务卡死。</p>
<p>可以通过Atomikos实现JTA/XA规范中的事务管理器</p>
<h3 id="TCC补偿（本次使用方案）"><a href="#TCC补偿（本次使用方案）" class="headerlink" title="TCC补偿（本次使用方案）"></a>TCC补偿（本次使用方案）</h3><p>将每个数据库操作拆分为流水操作和撤销操作，补偿事务模式将锁的粒度完全交给业务处理。事务管理器通知第一个数据库做事务操作，再通知第二个数据库做事务操作，如果第二数据库操作不成功，则进行撤销操作。</p>
<p>TCC在springcloud中通过熔断来实现，可以在熔断器中自定义补偿逻辑。<br>我这里没有用springcloud，广义来说，手动控制失败回滚，即在trycatch中删除，也是一种TCC实现。</p>
<h3 id="本地消息事务"><a href="#本地消息事务" class="headerlink" title="本地消息事务"></a>本地消息事务</h3><p>通过外部消息系统来保证事务的正确性，如Kafka。首先额外建立一个消息表，事务管理器将消息发到kafka中，有另一个应用的消费者消费处理数据。如果消费者处理数据异常，则把消费状态重新发到kafka中，进行重试。</p>
<h3 id="尽最大努力通知"><a href="#尽最大努力通知" class="headerlink" title="尽最大努力通知"></a>尽最大努力通知</h3><p>和本地消息事务基本一致，但是B数据库操作失败的时候，不会马上重新发送消息到kafka中，而通过梯度递增的定时查询方式，去主动失败操作，然后重试，在几次操作仍然失败后，则放弃。该方案表示，从系统的状态不会影响到主系统。</p>
<p>由于业务逻辑并不是很复杂，我使用了最简单的TCC实现，去掉@Transaction，在catch中做回滚操作。<br>关于分布式事务请参照我的另一篇博客</p>

        </div>
        
<blockquote class="copyright">
    <p><strong>本文链接 : </strong><a class="permalink" href="https://123zhangzhenbin.gitee.io/zzbomb/2020/09/18/202009171800-dynamic-datasource-with-transaction/">https://123zhangzhenbin.gitee.io/zzbomb/2020/09/18/202009171800-dynamic-datasource-with-transaction/</a></p>
    <p><strong>This article is available under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank" rel="noopener noreferrer">Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)</a> License</strong></p>
</blockquote>


    </article>
    
    <section id="comments">
        
    </section>


    

</main>


<aside style="" id="sidebar" class="aside aside-fixture">
    <div class="toc-sidebar">
        <nav id="toc" class="article-toc">
            <h3 class="toc-title">文章目录</h3>
            <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#背景"><span class="toc-number">1.</span> <span class="toc-text">背景</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#重现"><span class="toc-number">2.</span> <span class="toc-text">重现</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#DEBUG定位"><span class="toc-number">3.</span> <span class="toc-text">DEBUG定位</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#解决"><span class="toc-number">4.</span> <span class="toc-text">解决</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#两段事务提交"><span class="toc-number">4.1.</span> <span class="toc-text">两段事务提交</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#TCC补偿（本次使用方案）"><span class="toc-number">4.2.</span> <span class="toc-text">TCC补偿（本次使用方案）</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#本地消息事务"><span class="toc-number">4.3.</span> <span class="toc-text">本地消息事务</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#尽最大努力通知"><span class="toc-number">4.4.</span> <span class="toc-text">尽最大努力通知</span></a></li></ol></li></ol>
        </nav>
    </div>
</aside>





        </section>
        <footer class="hidden lg:block fixed bottom-0 left-0 sm:w-1/12 lg:w-1/6 bg-gray-100 z-40">
    
    <div class="footer-social-links">
        
            <a href="https://gitee.com/123zhangzhenbin" target="_blank" rel="noopener">
                <i class="iconfont icon-github"></i>
            </a>
        
    </div>
    
    <p style="display: block;text-align: center;font-size: 13px;"><a href="https://beian.miit.gov.cn/" target="_blank">粤ICP备16013026号</a></p>
    
        <p class="footer-custom"><a href="https://beian.miit.gov.cn/" target="_blank">粤ICP备16013026号</a></p>
        <p class="theme-brand">Theme by <a href="https://github.com/fengkx/hexo-theme-purer" target="_blank" rel="nofollow noopener noreferrer noopener">hexo-theme-purer</a></p>

    
</footer>

        <div id="mask" class="hidden mask fixed inset-0 bg-gray-900 opacity-75 z-40"></div>
        <div id="search-view-container" class="hidden shadow-xl"></div>
        
<script src="/zzbomb/js/dom-event.min.js"></script>

<script src="//cdn.jsdelivr.net/npm/yox@1.0.0-alpha.121/dist/standard/prod/yox.min.js"></script>


<script src="/zzbomb/js/search.min.js"></script>



    <script src="//cdn.jsdelivr.net/npm/lightgallery.js@1.1.3/dist/js/lightgallery.min.js"></script>
    
<script src="/zzbomb/js/light-gallery.min.js"></script>





    </body>
</html>
